package nostalgia.gui.forms;

import it.cnr.imaa.essi.lablib.gui.checkboxtree.CheckboxTree;

import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.*;
import java.util.*;
import java.io.File;

import nostalgia.collection.DirectoryCollectionReader;
import nostalgia.collection.DirectoryCollectionItem;
import nostalgia.lastfm.LastfmChartDataReader;
import nostalgia.lastfm.LastfmData;
import nostalgia.lastfm.model.Weeklytrackchart;
import nostalgia.lastfm.model.Track;
import nostalgia.playlist.M3UPlaylist;
import nostalgia.SystemConfiguration;

public class MainForm {
    private JPanel contentPanel;
    private JTree chartTree;
    private DefaultMutableTreeNode chartTreeRoot;
    private JTextField tracksTextField;
    private JComboBox comboBox1;
    private JButton createButton;
    private JButton saveButton;
    private JButton launchButton;
    private JButton configurationButton;
    private JList trackList;
    private Vector<TrackListEntry> trackListData;

    DirectoryCollectionReader collection;
    LastfmChartDataReader charts;

    public MainForm() {
        createButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onCreate();
            }
        });
        saveButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onSave();
            }
        });
        launchButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onLaunch();
            }
        });
        trackList.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                super.keyReleased(e);
                onTrackListKeyReleased(e);
            }
        });
    }

    public JPanel getContentPanel() {
        return contentPanel;
    }

    public JButton getConfigurationButton() {
        return configurationButton;
    }

    private void createUIComponents() {
        chartTreeRoot =
                new DefaultMutableTreeNode("Charts");
        chartTree = new CheckboxTree(chartTreeRoot);
        trackListData = new Vector<TrackListEntry>();
        trackList = new JList(trackListData);
    }

    public void load() {
        collection = new DirectoryCollectionReader();
        ProgressDialog.showDialog(null, "Reading local music collection", collection);
        charts = LastfmChartDataReader.getDefaultInstance();
        ProgressDialog.showDialog(null, "Reading last.fm track charts", charts);
        loadChartTree();
    }

    private void loadChartTree() {
        Iterator<Weeklytrackchart> it = charts.getCharts().iterator();
        while(it.hasNext()) {
            TrackChartTreeNode node = new TrackChartTreeNode(it.next());
            chartTreeRoot.add(node);
        }
        chartTreeRoot.setUserObject(charts.getWho() + "'s charts");
        chartTree.expandPath(new TreePath(chartTreeRoot));
    }

    private void onCreate() {
        // first create the set of playable tracks
        Map<DirectoryCollectionItem, Long> playable = new HashMap<DirectoryCollectionItem, Long>();
        long totalPlayCount = 0;
        TreePath[] checked = ((CheckboxTree)chartTree).getCheckingPaths();
        for(int i = 0; i < checked.length; i++) {
            if(checked[i].getLastPathComponent() instanceof TrackChartTreeNode) {
                TrackChartTreeNode checkedNode = (TrackChartTreeNode)checked[i].getLastPathComponent();
                Iterator<Track> it = checkedNode.getChart().getTrack().iterator();
                while(it.hasNext()) {
                    Track track = it.next();
                    DirectoryCollectionItem trackItem = new DirectoryCollectionItem();
                    trackItem.setArtist(track.getArtist().getValue());
                    trackItem.setTitle(track.getName());
                    DirectoryCollectionItem item = collection.getCollection().get(trackItem);
                    if(item != null) {
                        totalPlayCount += track.getPlaycount();
                        if(playable.containsKey(item)) {
                            playable.put(item, playable.get(item) + track.getPlaycount());
                        }
                        else {
                            playable.put(item, (long)track.getPlaycount());
                        }
                    }
                }
            }
        }

        // randomly select tracks from the list
        trackListData.clear();
        int playlistLength = 0;
        Random rand = new Random();
        try {
            playlistLength = Integer.parseInt(tracksTextField.getText());
        }
        catch(Exception e) {
            JOptionPane.showMessageDialog(null, "Please enter a valid track count value");
            return;
        }
        for(int i = 0; i < playlistLength && playable.size() > 0; i++) {
            long select = Math.abs(rand.nextLong()) % totalPlayCount;
            long cum = 0;
            Iterator<Map.Entry<DirectoryCollectionItem, Long>> it = playable.entrySet().iterator();;
            while(it.hasNext()) {
                Map.Entry<DirectoryCollectionItem, Long> entry = it.next();
                cum += entry.getValue();
                if(cum >= select) {
                    trackListData.add(new TrackListEntry(entry.getKey(), entry.getValue()));
                    playable.remove(entry.getKey());
                    break;
                }
            }
        }
        trackList.updateUI();
    }

    private void onSave() {
        JFileChooser chooser = new JFileChooser();
        //chooser.setCurrentDirectory(new File(System.getProperty("user.home")));
        chooser.setDialogTitle("Save playlist");
        FileFilter fileFilter = new FileFilter() {
            public boolean accept(File f) {
                return f.isDirectory() || f.getName().endsWith(".m3u");
            }

            public String getDescription() {
                return "m3u playlist";
            }
        };
        chooser.setFileFilter(fileFilter);
        if(chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
            // TODO: confirm overwritting existing file
            File selectedFile = chooser.getSelectedFile();
            String path = selectedFile.getAbsolutePath();
            if(selectedFile.getName().indexOf('.') < 0) {
                path += ".m3u";
            }
            savePlaylist(path);
        }
    }

    private void onLaunch() {
        File playlistDirectory = new File(SystemConfiguration.getInstsance().getUserDataDirectory(),
                "playlists");
        if(!playlistDirectory.exists()) {
            playlistDirectory.mkdirs();
        }
        try {
            File file = File.createTempFile("playlist", ".m3u", playlistDirectory);
            savePlaylist(file.getAbsolutePath());
            Desktop.getDesktop().open(file);
        }
        catch(Exception e) {
            JOptionPane.showMessageDialog(null, "The playlist could not be launched.");
            e.printStackTrace();
        }
    }

    private void savePlaylist(String path) {
        M3UPlaylist playlist = new M3UPlaylist();
        Iterator<TrackListEntry> it = trackListData.iterator();
        while(it.hasNext()) {
            playlist.add(it.next().item);
        }
        try {
            playlist.save(new File(path));
        }
        catch(Exception e) {
            JOptionPane.showMessageDialog(null, "The playlist could not be saved.");
            e.printStackTrace();
        }
    }


    private void onTrackListKeyReleased(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_DELETE) {
            Object[] selected = trackList.getSelectedValues();
            for(int i = 0; i < selected.length; i++) {
                trackListData.remove(selected[i]);
            }
            trackList.updateUI();
        }
    }

    private static class TrackChartTreeNode extends DefaultMutableTreeNode {
        private Weeklytrackchart chart;
        public TrackChartTreeNode(Weeklytrackchart chart) {
            super(LastfmData.dateFormat.format(LastfmData.getDateFromChart(chart.getFrom()))
                    +  " (" + getTotalPlaycount(chart) + " )");
            this.chart = chart;
        }

        public Weeklytrackchart getChart() {
            return chart;
        }

        protected static long getTotalPlaycount(Weeklytrackchart chart) {
            long fctval = 0;
            Iterator<Track> it = chart.getTrack().iterator();
            while(it.hasNext()) {
                fctval += it.next().getPlaycount();
            }
            return fctval;
        }
    }

    private static class TrackListEntry {
        private DirectoryCollectionItem item;
        private long playcount;

        public TrackListEntry(DirectoryCollectionItem item, long playcount) {
            this.item = item;
            this.playcount = playcount;
        }

        @Override
        public String toString() {
            return item.getArtist() + " - " + item.getTitle() + " (" + playcount + ")";
        }
    }
}
